#include "cube.h"

CCube::CCube(void)
{

}

CCube::~CCube(void)
{}

void CCube::parseMessage(Message& msg, vector<Message>& retMsg)
{
	switch(msg.MsgCode)
	{
	case MSG_INIT:
		{
			std::ifstream f1("cube.dat", std::ios::binary);

			int xs,ys,zs;
			f1 >> xs >> ys >> zs;

			cube = make_shared<CArray3D>(xs,ys,zs);

			char c;

			for(int k=0; k < zs; k++)
				for(int j=ys-1; j >= 0; j--)
					for(int i=0; i < xs; i++)
					{
						f1 >> c;
						(*cube)(i,j,k) = c;
					}
			f1.close();
		}
		break;
	case MSG_UPDATE:
		{
			Message m("Cube","Keyboard",MSG_GET_PRESSED_KEYS);
			retMsg.push_back(m);
		}
		break;
	case MSG_PRESSED_KEYS:
		{
			Message m;
			PKeys k = dynamic_pointer_cast<CKeys>(msg.Data);
			
			if(k->keys.find('1')!=string::npos)
			{
				Rotate(ROT_LEFT);
			}
			else if(k->keys.find('3')!=string::npos)
			{
				Rotate(ROT_RIGHT);
			}
			else if(k->keys.find('9')!=string::npos)
			{
				Rotate(ROT_CLKWISE);
			}
			else if(k->keys.find('7')!=string::npos)
			{
				Rotate(ROT_CCLKWISE);
			}
		}
		break;
	case MSG_SET_CRSECTION:
		{		// Hero sends on rotation
			PCoords heroCoords = dynamic_pointer_cast<CCoords>(msg.Data);
			crSection = getCrossSection(heroCoords);
		}
		break;
	case MSG_GET_SIZE:
		{
			Message m("Cube", msg.From, MSG_CUBE_SIZE, cube->getSize());
			retMsg.push_back(m);
		}
		break;
	case MSG_GET_CRSECTION:
		{
			Message m("Cube", msg.From, MSG_CUBE_CRSECTION, crSection);
			retMsg.push_back(m);
		}
		break;
	case MSG_DRAW_L1:
		{
			// Drawing cube's cross-section, visible layer
			PArray2D disp = dynamic_pointer_cast<CArray2D>(msg.Data);
			int x0 = ( disp->getXsize()-crSection->getXsize() )/2;
			int y0 = ( disp->getYsize()-crSection->getYsize() )/2;

			for(int i=0; i<crSection->getXsize(); i++)
				for(int j=0; j<crSection->getYsize(); j++)
				{
					if( (*crSection)(i,j)>=128 ) (*disp)(x0+i,y0+j)='o';
					else (*disp)(x0+i,y0+j)=(*crSection)(i,j);
				}
		}
		break;
	}
}

void CCube::Rotate(int direction)
{
	PArray3D rotatedCube;

	int xsize = cube->getXsize();
	int ysize = cube->getYsize();
	int zsize = cube->getZsize();

	switch(direction)
	{
	case ROT_LEFT:
		rotatedCube = make_shared<CArray3D>(zsize, ysize, xsize);
		for(int i=0; i < xsize; i++)
			for(int j=0; j < ysize; j++)
				for(int k=0; k < zsize; k++)
					(*rotatedCube)(zsize-k-1, j, i) = (*cube)(i,j,k);
		break;

	case ROT_RIGHT:
		rotatedCube = make_shared<CArray3D>(zsize, ysize, xsize);
		for(int i=0; i < xsize; i++)
			for(int j=0; j < ysize; j++)
				for(int k=0; k < zsize; k++)
					(*rotatedCube)(k, j, xsize-i-1) = (*cube)(i,j,k);
		break;

	case ROT_CLKWISE:
		rotatedCube = make_shared<CArray3D>(ysize, xsize, zsize);
		for(int i=0; i < xsize; i++)
			for(int j=0; j < ysize; j++)
				for(int k=0; k < zsize; k++)
					(*rotatedCube)(j, xsize-i-1, k) = (*cube)(i,j,k);
		break;

	case ROT_CCLKWISE:
		rotatedCube = make_shared<CArray3D>(ysize, xsize, zsize);
		for(int i=0; i < xsize; i++)
			for(int j=0; j < ysize; j++)
				for(int k=0; k < zsize; k++)
					(*rotatedCube)(ysize-j-1, i, k) = (*cube)(i,j,k);
		break;
	}
	cube = rotatedCube;
}

PArray2D CCube::getSurrCells(const PCoords& pos)
{
	PArray2D surrCells = make_shared<CArray2D>(3,3);
	for(int i=0; i<3; i++)
		for(int j=0; j<3; j++)
			(*surrCells)(i,j)=(*cube)(pos->getX()+i-1,pos->getY()+j-1,pos->getZ());
	return surrCells;
}

PArray2D CCube::getCrossSection(const PCoords& pos)
{
	PArray2D crSec = make_shared<CArray2D>(cube->getXsize(),cube->getYsize());
	for(int i=0; i < cube->getXsize(); i++)
		for(int j=0; j < cube->getYsize(); j++)
		{
			if( (*cube)(i, j, pos->getZ()) == '.')
			{
				if( (*cube)(i, j, pos->getZ()-1) == '.') 	
					(*crSec)(i,j) =' ';
				else
					(*crSec)(i,j) ='.';
			}
			else
				(*crSec)(i,j) = (*cube)(i,j,pos->getZ());
		}
	return crSec;
}
